﻿using System;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Daemon;
using JetBrains.ReSharper.Daemon.Stages;
using JetBrains.ReSharper.Daemon.Stages.Dispatcher;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.Tree;
using SPCAFContrib.Entities.Consts;
using SPCAFContrib.ReSharper.Common;
using SPCAFContrib.ReSharper.Common.Attributes;
using SPCAFContrib.ReSharper.Common.CodeAnalysis;
using SPCAFContrib.ReSharper.Common.Extensions;
using SPCAFContrib.ReSharper.Consts;
using SPCAFContrib.ReSharper.Inspection.Code;

[assembly: RegisterConfigurableSeverity(LastParameterForAddWorkItemShouldBeEmptyHighlighting.CheckId,
  null,
  Consts.CORRECTNESS_GROUP,
  LastParameterForAddWorkItemShouldBeEmptyHighlighting.CheckId + ": " + LastParameterForAddWorkItemShouldBeEmptyHighlighting.Message,
  "Specify gProcessingId parameter for SPSite.AddWorkItem() as Guid.Empty. Overwise it fail.",
  Severity.WARNING,
  false, Internal = false)]

namespace SPCAFContrib.ReSharper.Inspection.Code
{
    [ElementProblemAnalyzer(new[] { typeof(IReferenceExpression) }, HighlightingTypes = new[] { typeof(LastParameterForAddWorkItemShouldBeEmptyHighlighting) })]
    [Applicability(
        IDEProjectType.SP2010FarmSolution |
        IDEProjectType.SPSandbox |
        IDEProjectType.SP2013FarmSolution |
        IDEProjectType.SPServerAPIReferenced)]
    public class ProcessingIdParameterForAddWorkItemShouldBeEmpty : ElementProblemAnalyzer<IReferenceExpression>
    {
        protected override void Run(IReferenceExpression element, ElementProblemAnalyzerData analyzerData, IHighlightingConsumer consumer)
        {
            IPsiSourceFile sourceFile = element.GetSourceFile();

            if (sourceFile != null)
            {
                if (sourceFile.HasExcluded(analyzerData.SettingsStore)) return;

                IProject project = sourceFile.GetProject();

                if (project != null)
                {
                    if (project.IsApplicableFor(this))
                    {
                        if (IsInvalid(element))
                        {
                            consumer.AddHighlighting(new LastParameterForAddWorkItemShouldBeEmptyHighlighting(element),
                                element.GetDocumentRange(),
                                element.GetContainingFile());
                        }
                    }
                }
            }
        }

        public static bool IsInvalid(IReferenceExpression element)
        {
            bool result = false;
            IExpressionType expressionType = element.GetExpressionType();
            if (expressionType.IsResolved &&
                element.IsResolvedAsMethodCall(ClrTypeKeys.SPSite,
                    new[] {new MethodCriteria() {ShortName = "AddWorkItem"}}))
            {
                ICSharpExpression containingExpression = element.GetContainingExpression();
                if (containingExpression is IInvocationExpression)
                {
                    IInvocationExpression invocationExpression = containingExpression as IInvocationExpression;
                    TreeNodeCollection<ICSharpArgument> arguments = invocationExpression.Arguments;
                    if (arguments.Count > 2)
                    {
                        var argument = arguments.Count == 13 ? arguments.Last() : arguments[arguments.Count - 2];
                        bool isGuidEmpty = argument.IsReferenceOfPropertyUsage(ClrTypeKeys.Guid, new[] {"Empty"});
                        bool isNewGuid = !isGuidEmpty && (argument.Value is IObjectCreationExpression) &&
                        (argument.Value as IObjectCreationExpression).Arguments.Count == 0 && 
                        argument.Value.IsOneOfTypes(new[] { ClrTypeKeys.Guid });
                        if (!isGuidEmpty && !isNewGuid)
                        {
                            result = true;           
                        }
                    }
                }
            }

            return result;
        }
    }

    [ConfigurableSeverityHighlighting(CheckId, CSharpLanguage.Name, OverlapResolve = OverlapResolveKind.NONE, ShowToolTipInStatusBar = true)]
    public class LastParameterForAddWorkItemShouldBeEmptyHighlighting : IHighlighting
    {
        public const string CheckId = CheckIDs.Rules.Assembly.ProcessingIdParameterForAddWorkItemShouldBeEmpty;
        public const string Message = "gProcessingId parameter have to be Guid.Empty";

        public IReferenceExpression Element { get; private set; }
        public LastParameterForAddWorkItemShouldBeEmptyHighlighting(IReferenceExpression element)
        {
            this.Element = element;
        }

        #region IHighlighting Members

        public string ToolTip
        {
            get
            {
                return String.Format("{0}: {1}", CheckId, Message);
            }
        }
        public string ErrorStripeToolTip
        {
            get { return ToolTip; }
        }

        public int NavigationOffsetPatch
        {
            get { return 0; }
        }

        public bool IsValid()
        {
            return this.Element != null && this.Element.IsValid();
        }

        #endregion
    }
}
